package search.service.search;

import com.fasterxml.jackson.databind.ObjectMapper;

import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.Strings;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import org.springframework.stereotype.Component;
import search.config.AnalyzerNames;
import common.dao.elastic.ElasticSearchDao;
import common.config.IndexTypeNames;
import common.helper.json.JsonFormatter;
import search.service.analysis.EncodeDecode;

import javax.inject.Inject;

import java.util.List;

@Component
public class SimpleSearchService_V1 {
    final Logger logger = LoggerFactory.getLogger(SimpleSearchService_V1.class);

    private final ObjectMapper mapper;
    private final ElasticSearchDao elasticsearchDao;

    @Inject
    public SimpleSearchService_V1(
                         ElasticSearchDao elasticsearchDao,
                         ObjectMapper mapper) {
        this.mapper = mapper;
        this.elasticsearchDao = elasticsearchDao;
    }


	//*******************************************//
	/*
	 * simple search
	 * using fulltext, used for search from url, with GET Method
	 * <<search>>
	 */
	public String search(String q,  Integer from, Integer size, String mediatype, String sorttype, String explain, String dsl) {
		/*
		 * query
		 */
		QueryBuilder query;
		// If the user does not provide any text to query, let's match all documents
		if (!Strings.hasText(q)) {
			query = QueryBuilders.matchAllQuery();
		} 
		else {
			BoolQueryBuilder multi = QueryBuilders.boolQuery();
			SimpleQueryStringBuilder string_query = QueryBuilders.
					simpleQueryStringQuery(q)
					.field("_all");
			BoolQueryBuilder global = QueryBuilders.boolQuery();
			String minimum = AnalyzerNames.minimumShouldMatch;
			global.must(
					string_query
							.analyzer(AnalyzerNames.analyzers_v2[0])
							.minimumShouldMatch(minimum)
			);
			multi.must(
					global.boost(AnalyzerNames.boosting_v2[0])
			)
			;

			for(int i = 1; i < AnalyzerNames.counter_v2; i++){
				BoolQueryBuilder wrapper = QueryBuilders.boolQuery();
				SimpleQueryStringBuilder base = QueryBuilders.
						simpleQueryStringQuery(q)
						.field("_all");
				multi.should(
						wrapper.should(
								base.analyzer(AnalyzerNames.analyzers_v2[i])
								.minimumShouldMatch("0")
						).boost(AnalyzerNames.boosting_v2[i])
				);
			}
			multi.minimumShouldMatch("0");
			query = multi;
		}


		/*
		 * filter
		 * mediatype
		 */
		QueryBuilder filter = null;
		if(mediatype == null || mediatype.equals("")){
			mediatype = "video";
		}
		else if(!mediatype.equals("video") && !mediatype.equals("audio")
				&& !mediatype.equals("picture")){
			mediatype = "video";
		}
		else{
			/*
			 * 元数据中没有相关域，有待添加
			 */
			//filter.xxx
			mediatype = "video";
		}
		
		/*
		 * filteredQuery
		 */
		FilteredQueryBuilder filteredQuery = QueryBuilders.filteredQuery(
				query,
				filter
				);
		
		/*
		 * sort , from , size
		 */
		String sortfield = "_score";
		SortOrder order = SortOrder.DESC;
		if(sorttype == null || sorttype.equals(""))
			sorttype = "relevancy";
		else if(!sorttype.equals("relevancy") && !sorttype.equals("earliest") && !sorttype.equals("latest"))
			sorttype = "relevancy";
		
		if(sorttype.equals("relevancy")){
			sortfield = "_score";
			order = SortOrder.DESC;
		}
		else if(sorttype.equals("earliest")){
			sortfield = "Metadata.UploadDate";
			order = SortOrder.ASC;
		}
		else if(sorttype.equals("latest")){
			sortfield = "Metadata.UploadDate";
			order = SortOrder.DESC;
		}
		/*
		 * 还没有时间相关属性，先使用默认
		 */
		sortfield = "_score";
		order = SortOrder.DESC;
		SortBuilder sort = new FieldSortBuilder(sortfield).order(order).ignoreUnmapped(true);

		/*
		* levels
		 */
		List<String> levels = IndexTypeNames.MediaDB.getTableTypeList();

		/*
		* explain
		 */
		Boolean is_explain = EncodeDecode.is_explain(explain);

		/*
		 * dsl
		 */
		Boolean is_dsl = EncodeDecode.is_dsl(dsl);
		if(is_dsl == true){
			SearchRequestBuilder request = this.elasticsearchDao.genSearchRequset(filteredQuery, from, size, sort, levels , is_explain);
			return request.toString();
		}

		/*
		 * search 
		 */
		SearchResponse response = elasticsearchDao.search(filteredQuery, from, size, sort, levels , is_explain);

		if (logger.isDebugEnabled()) logger.debug("search({})={} hits", q, response.getHits().getTotalHits());

		//return response.toString();
		return JsonFormatter.formatSearchResponse(response);
	}

	public static void main(String[] args){
		SimpleSearchService_V1 service = new SimpleSearchService_V1(new ElasticSearchDao("debug") , new ObjectMapper());
		String result = service.search("北京市车流", 0, 10 ,"video", "relevancy", "true", "true");
		System.out.println(result);
	}

}
